package com.company.modules.sys.controller;

import com.company.common.utils.R;
import com.company.modules.project.entity.Company;
import com.company.modules.project.entity.Employee;
import com.company.modules.project.entity.LoginAuthor;
import com.company.modules.project.service.CompanyService;
import com.company.modules.project.service.EmployeeService;
import com.company.modules.project.service.ForgetPasswordService;
import com.company.modules.project.service.LoginAuthorService;
import com.company.modules.project.util.HostHolder;
import com.company.modules.project.util.HrmUtil;
import com.company.modules.sys.entity.SysUserEntity;
import com.company.modules.sys.form.ForgetPasswordForm;
import com.company.modules.sys.form.SysLoginForm;
import com.company.modules.sys.service.SysCaptchaService;
import com.company.modules.sys.service.SysUserService;
import com.company.modules.sys.service.SysUserTokenService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 登录相关
 *
 * @author Mark sunlightcs@gmail.com
 */
@RestController
public class SysLoginController extends AbstractController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserTokenService sysUserTokenService;
    @Autowired
    private SysCaptchaService sysCaptchaService;
    @Autowired
    private LoginAuthorService loginAuthorService;
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private ForgetPasswordService forgetPasswordService;
    @Autowired
    private HostHolder hostHolder;

    /**
     * 验证码
     */
    @GetMapping("captcha.jpg")
    public void captcha(HttpServletResponse response, String uuid) throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        //获取图片验证码
        BufferedImage image = sysCaptchaService.getCaptcha(uuid);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }

    /**
     * 登录
     */
    @PostMapping("/sys/login")
    public Map<String, Object> login(@RequestBody SysLoginForm form) throws IOException {
        boolean captcha = sysCaptchaService.validate(form.getUuid(), form.getCaptcha());
        if (!captcha) {
            return R.error("验证码不正确");
        }
        //用户信息
        SysUserEntity user = sysUserService.queryByUserName(form.getUsername());

        //账号不存在、密码错误
        if (user == null || !user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex())) {
            return R.error("账号或密码不正确");
        }
        //账号锁定
        if (user.getStatus() == 0) {
            return R.error("账号已被锁定,请联系管理员");
        }
        //生成token，并保存到数据库
        R r = sysUserTokenService.createToken(user.getUserId());
        return r;
    }

    /**
     * 发送验证码
     *
     * @param form 发送验证码的表单
     * @return 发送的反馈
     */
    @RequestMapping(value = "/sys/forget-password/confirm", method = RequestMethod.POST)
    public R forgetPassword(@RequestBody ForgetPasswordForm form) {
        String account = form.getAccount();
        String newPassword = form.getNewPassword();
        String confirmPassword = form.getConfirmPassword();
        String verify = form.getVerify();
        if (StringUtils.isBlank(account) || StringUtils.isBlank(newPassword) || StringUtils.isBlank(confirmPassword) || StringUtils.isBlank(verify)) {
            return R.error("您的输入有误，请重新输入");
        }
        // 检查两次密码是否相同
        if (!newPassword.equals(confirmPassword)) {
            return R.error("您两次输入的密码不一致，请重新输入");
        }
        LoginAuthor loginAccount = loginAuthorService.findLoginAuthorByLoginAccount(account);
        // 登录账户判空
        if (loginAccount == null) {
            return R.error("您的输入有误");
        }
        // TODO: 如果验证码不等于 Redis 中存储的验证码，判错
        synchronized (this) {
            // 获取 redis 中的验证码
            String verifyCode = forgetPasswordService.getVerifyCode(account);
            // 判断两者是否相等
            if (verifyCode.equals(verify)) {
                Integer userId = loginAccount.getUserId();
                String salt = HrmUtil.generateSalt();
                int i = loginAuthorService.modifyLoginAuthorPassword(userId, HrmUtil.md5(confirmPassword + salt), salt);
                if (i >= 1) {
                    // 表示密码修改成功
                    // 生成token，并保存到数据库
                    R r = sysUserTokenService.createToken(userId);
                    // 删除缓存中已存在的数据
                    forgetPasswordService.deleteVerifyCode(account);
                    return r.put("msg", "修改成功，正在返回登录页面......");
                } else {
                    return R.error("修改失败，请检查您的输入");
                }
            } else {
                // 两者不相等，提示用户重新输入
                return R.error("您的验证码有误，请重新输入");
            }
        }
    }

    @RequestMapping(path = "/sys/forget-password/send-verify", method = RequestMethod.POST)
    public R getVerify(@RequestBody ForgetPasswordForm form) {
        String account = form.getAccount();
        // 判断是否为邮箱
        String pattern = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";
        boolean match = Pattern.matches(pattern, account);
        if (!match) {
            // 不是邮件，提示账户错误
            return R.error("您输入的账户不是邮件，目前仅支持邮件形式的验证码");
        }
        LoginAuthor loginAccount = loginAuthorService.findLoginAuthorByLoginAccount(account);
        Employee employee = employeeService.findEmployeeById(loginAccount.getUserId());
        Company company = companyService.findCompanyById(employee.getCompanyId());
        // 生成邮件主题
        String subject = "[" + company.getName() + "]" + "找回密码";
        // 生成验证码
        String verifyCode = HrmUtil.generateVerifyCode(6);
        synchronized (this) {
            // 生成 Redis 并且存储，保证为原子操作，需要加锁
            forgetPasswordService.setVerifyCode(account, verifyCode);
            forgetPasswordService.sendForgetPasswordVerify(subject, account, verifyCode);
        }
        // 生成token，并保存到数据库
        R r = sysUserTokenService.createToken(loginAccount.getUserId());
        return r.put("msg", "验证码发送成功！");
    }


    /**
     * 退出
     */
    @PostMapping("/sys/logout")
    public R logout() {
        sysUserTokenService.logout(getUserId());
        return R.ok();
    }

}
